<template>
  <div class="default-search-form">
    <el-form
      ref="form"
      :inline="true"
      :rules="formRules"
      :model="formData"
      :label-width="style.labelWidth"
    >
      <template v-for="(item, key) in formItems">
        <el-form-item
          :label="item.label"
          v-show="checkItemShow(item)"
          :label-width="item.labelWidth"
          :prop="item.fieldList ? item.fieldList[0] : item.field"
          class="no-required-dot"
        >
          <template v-slot:label>
            <template
              v-if="
                item.type === 'checkbox' &&
                  !item.multiple &&
                  item.labelPosition === 'right'
              "
            >
              <el-checkbox
                class="single"
                v-model="formData[item.field]"
                @change="onItemDataChange(item)"
                :disabled="checkItemDisabled(item)"
                :true-label="item.trueValue"
                :false-label="item.falseValue"
              ></el-checkbox>
            </template>
            <template v-else>
              <span class="label-wrap">
                <span>{{ item.label }}</span>
              </span>
            </template>
          </template>
          <template v-if="item.type === 'INPUT' && !item.fieldList">
            <el-input
              v-model="formData[item.field]"
              :suffix-icon="item.icon"
              :type="item.inputType"
              :rows="item.rows"
              :placeholder="getItemPlaceholder(item)"
              @input="onItemDataChange(item, 'input')"
              @change="onItemDataChange(item)"
              clearable
              @click.native="onItemClick(item)"
              @focus="onItemFocus(item)"
              @blur="onItemBlur(item)"
              :disabled="checkItemDisabled(item)"
            >
              <template v-if="item.unit" slot="append">{{
                item.unit
              }}</template>
            </el-input>
          </template>
          <template v-if="item.type === 'INPUT' && item.fieldList">
            <el-input
              v-model="formData[item.fieldList[0]]"
              :suffix-icon="item.icon"
              :type="item.inputType"
              :rows="item.rows"
              :placeholder="getItemPlaceholder(item, { inputAlign: 'left' })"
              @input="onItemDataChange(item, 'input')"
              @change="onItemDataChange(item)"
              @click.native="onItemClick(item)"
              @focus="onItemFocus(item)"
              @blur="onItemBlur(item)"
              :disabled="checkItemDisabled(item, { inputAlign: 'left' })"
              :style="getItemStyle(item, { inputAlign: 'left' })"
            ></el-input>
            <el-input
              v-model="formData[item.fieldList[1]]"
              :suffix-icon="item.icon"
              :type="item.inputType"
              :rows="item.rows"
              :placeholder="getItemPlaceholder(item, { inputAlign: 'right' })"
              @input="onItemDataChange(item, 'input')"
              @change="onItemDataChange(item)"
              @click.native="onItemClick(item)"
              @focus="onItemFocus(item)"
              @blur="onItemBlur(item)"
              :disabled="checkItemDisabled(item, { inputAlign: 'right' })"
              :style="getItemStyle(item, { inputAlign: 'right' })"
            ></el-input>
          </template>
          <template v-if="item.type === 'SELECT' && !item.custom">
            <el-select
              v-model="formData[item.field]"
              :multiple="item.multiple"
              :collapse-tags="item.multiple"
              :placeholder="getItemPlaceholder(item)"
              @change="onItemDataChange(item)"
              clearable
              :disabled="checkItemDisabled(item)"
            >
              <el-option
                v-for="opt in getItemOptions(item)"
                :key="opt.code"
                :value="opt.code"
                :label="opt.name"
              ></el-option>
            </el-select>
          </template>
          <template v-if="item.type === 'DATE'">
            <el-date-picker
              v-model="formData[item.field]"
              type="date"
              :placeholder="getItemPlaceholder(item)"
              @change="onItemDataChange(item)"
              :disabled="checkItemDisabled(item)"
              :value-format="item.format"
              :picker-options="getItemDateOptions(item)"
            ></el-date-picker>
          </template>
          <template v-if="item.type === 'datetime'">
            <el-date-picker
              v-model="formData[item.field]"
              type="datetime"
              :placeholder="getItemPlaceholder(item)"
              @change="onItemDataChange(item)"
              :disabled="checkItemDisabled(item)"
              :value-format="item.format"
            ></el-date-picker>
          </template>
          <template v-if="item.type === 'daterang'">
            <el-date-picker
              v-model="baseFormData[item.field]"
              type="daterange"
              :placeholder="getItemPlaceholder(item)"
              @change="onItemDataChange(item)"
              :disabled="checkItemDisabled(item)"
              :value-format="item.format"
              :range-separator="item.separator"
              :start-placeholder="item.startPlaceholder"
              :end-placeholder="item.endPlaceholder"
              :unlink-panels="true"
            ></el-date-picker>
          </template>
        </el-form-item>
      </template>
      <el-form-item :label-width="style.labelWidth" label=" ">
        <slot name="btn-wrap"></slot>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      style: {},
      formRules: {},
      // 存放零时变量，比如 daterange 里面的 v-model
      baseFormData: {},
      // 存放一些双字段的初始值数据，给form的reset方法使用
      formResetData: {},
      // 存放baseFormData的初始值，给form的reset方法使用
      baseFormResetData: {}
    };
  },
  props: {
    readOnly: { type: Boolean, default: false },
    formData: {
      type: Object,
      default: function() {
        return {};
      }
    },
    formItems: {
      type: Array,
      default: function() {
        return [];
      }
    },
    formStyle: {
      type: Object,
      default: function() {
        return {};
      }
    }
  },
  watch: {
    formItems: function(list) {
      this.setFormItemsData();
      this.setFormData();
      this.setFormRulesData();
    },
    formStyle: {
      handler(val) {
        console.log("变动", val);
        this.setFormStyleDefault();
      },
      deep: true
    }
  },
  methods: {
    // 从值集默认值设置表单字段值
    setFormData: function() {
      this.formItems.forEach(item => {
        if (
          this.isSet(item.field) &&
          typeof this.formData[item.field] === "undefined"
        ) {
          if (item.type === "checkbox") {
            if (item.multiple === true) {
              this.$set(this.formData, item.field, []);
            } else {
              if (typeof item.falseValue === "undefined") {
                this.$set(this.formData, item.field, false);
              } else {
                this.$set(this.formData, item.field, item.falseValue);
              }
            }
          } else if (item.type === "SELECT" && (item.custom || item.multiple)) {
            this.$set(this.formData, item.field, []);
          } else if (item.type === "outbox") {
            if (item.fieldList) {
              // 放到下面处理赋值了
            } else {
              if (item.multiple === true) {
                this.$set(this.formData, item.field, []);
              } else {
                this.$set(this.formData, item.field, "");
              }
            }
          } else if (item.type === "daterang") {
            // 放到下面处理赋值了
          } else {
            this.$set(this.formData, item.field, "");
          }
        } else {
          if (item.type === "outbox" && item.multiple) {
          }
        }

        if (item.type === "INPUT" && item.fieldList) {
          let [field1, field2] = item.fieldList;
          if (typeof this.formData[field1] === "undefined") {
            this.$set(this.formData, field1, "");
          }
          if (typeof this.formData[field2] === "undefined") {
            this.$set(this.formData, field2, "");
          }
        }
        if (item.type === "INPUT" && !item.fieldList) {
          this.$set(this.formData, item.field, "");
          console.log(this.formData, 888);
        }
        if (item.type === "outbox" && item.fieldList) {
          let baseFormField = item.fieldList.join(",");
          let [valueField, labelField] = item.fieldList;
          if (typeof this.formData[valueField] !== "undefined") {
            this.$set(this.baseFormData, baseFormField, [
              this.formData[valueField],
              this.formData[labelField]
            ]);
          } else {
            this.$set(this.baseFormData, baseFormField, []);
            this.$set(this.formData, valueField, "");
            this.$set(this.formData, labelField, "");
          }

          this.$watch("formData", () => {
            this.baseFormData[baseFormField] = [
              this.formData[valueField],
              this.formData[labelField]
            ];
          });
        }

        if (item.type === "daterang") {
          let baseFormField = item.fieldList.join(",");
          let [startField, endField] = item.fieldList;
          if (typeof this.formData[startField] !== "undefined") {
            this.$set(this.baseFormData, baseFormField, [
              this.formData[startField],
              this.formData[endField]
            ]);
          } else {
            this.$set(this.baseFormData, baseFormField, []);
            this.$set(this.formData, startField, "");
            this.$set(this.formData, endField, "");
          }

          this.$watch("formData", () => {
            this.baseFormData[baseFormField] = [
              this.formData[startField],
              this.formData[endField]
            ];
          });
        }
      });
    },
    // 配置默认字段值给重置方法
    setFormResetData: function() {
      console.log(333);
      this.formItems.forEach(item => {
        if (item.type === "INPUT" && item.fieldList) {
          let field = item.fieldList[1];
          // if (!this.isSet(this.formResetData[field])) {
          this.formResetData[field] = this.formData[field];
          // }
        }
        if (item.type === "daterang" && item.fieldList) {
          let field = item.fieldList[1];
          // if (!this.isSet(this.formResetData[field])) {
          this.formResetData[field] = this.formData[field];
          // }
        }
        if (item.type === "outbox" && item.fieldList) {
          let field = item.fieldList[1];
          // if (!this.isSet(this.formResetData[field])) {
          this.formResetData[field] = this.formData[field];
          // }
        }
      });
      for (let field in this.baseFormData) {
        // if (!this.isSet(this.baseFormResetData[field])) {
        this.baseFormResetData[field] = JSON.stringify(
          this.baseFormData[field]
        );
        // }
      }
    },
    // 对表单传参 formItems 进行默认赋值、校验等初始化的操作
    setFormItemsData: function() {
      this.formItems.forEach(item => {
        item.rows = parseInt(item.rows) || null;
        item.decimal = parseInt(item.decimal) || 0;
        item.max =
          parseFloat(item.max) || parseFloat(item.max) === 0
            ? parseFloat(item.max)
            : null;
        item.min =
          parseFloat(item.min) || parseFloat(item.min) === 0
            ? parseFloat(item.min)
            : null;
        if (!item.opt_pre) {
          item.opt_pre = "请选择";
        }
        if (!item.type) {
          item.type = "INPUT";
        }
        if (item.type === "INPUT") {
          item.opt_pre = "请输入";
        }
        if (!item.size) {
          if (item.type === "checkbox" && item.multiple) {
            item.size = 3;
          } else {
            item.size = 1;
            if (!item.labelPosition) {
              item.labelPosition = "right";
            }
          }
        }
        if (item.type === "INPUT" && item.rows > 1) {
          item.inputType = "textarea";
        }
        if (
          typeof item.placeholder !== "string" &&
          !this.isArray(item.placeholder)
        ) {
          if (item.type === "DATE" || item.type === "datetime") {
            item.placeholder = "请选择日期";
          } else {
            item.placeholder = item.opt_pre + item.label;
          }
        }
        if (item.type === "DATE" && !item.format) {
          item.format = "yyyy-MM-dd";
        }
        if (item.type === "datetime" && !item.format) {
          item.format = "yyyy-MM-dd HH:mm:ss";
        }
        if (item.type === "daterang") {
          if (!this.isArray(item.fieldList)) {
            console.error("daterang 的 field字段必须为数组对象");
            return;
          }
          if (item.fieldList.length !== 2) {
            console.error("daterang 的 field字段必须为两个成员的数组");
            return;
          }
          item.field = item.fieldList.join(",");
          item.format = "yyyy-MM-dd";
          if (typeof item.autoTime !== "boolean") {
            item.autoTime = true;
          }
          if (!item.separator) item.separator = "~";
          if (!item.startPlaceholder) item.startPlaceholder = "开始日期";
          if (!item.endPlaceholder) item.endPlaceholder = "结束日期";
        }
        if (item.type === "outbox" && item.fieldList) {
          if (!this.isArray(item.fieldList)) {
            console.error("outbox 的 fieldList字段必须为数组对象");
            return;
          }
          if (item.fieldList.length !== 2) {
            console.error("outbox 的 fieldList字段必须为两个成员的数组");
            return;
          }
          item.field = item.fieldList.join(",");
          item.placeholder = "请选择";
        }
        if (item.type === "checkbox" && !item.multiple) {
          if (item.useDictionary === true) {
            item.trueValue = this.Dictionary.IS_TRUE;
            item.falseValue = this.Dictionary.IS_FALSE;
          }
          if (typeof item.falseValue !== typeof item.trueValue) {
            console.error(
              `[${item.label}:${item.field}] 的 falseValue 和 trueValue 必须同时定义`
            );
          }
        }
        if (item.type === "SELECT" && item.childDictionary) {
          let childItem = this.getItem(item.childDictionary);
          let parentField = item.field;
          if (this.isArray(childItem.options)) {
            childItem._options = JSON.parse(JSON.stringify(childItem.options));
            childItem.options = ({ item }) => {
              let parentCode = this.getItemValue(parentField);
              return item._options.filter(opt => opt.parentCode === parentCode);
            };
          }
        }
      });
    },
    // 对表单校验规则初始化
    setFormRulesData: function() {
      let formRules = {};
      this.formItems.forEach(item => {
        let itemRule = item.rule || [];
        if (item.required) {
          let trigger = ["blur", "change"];
          let rule = {
            required: true,
            message: item.opt_pre + item.label,
            trigger: trigger
          };
          itemRule.push(rule);
        }

        if (item.minLength) {
          let validator = this.$validator.formRule("minLength", {
            length: item.minLength
          });
          itemRule.push({ validator: validator, trigger: ["blur", "change"] });
        }

        if (item.maxLength) {
          let validator = this.$validator.formRule("maxLength", {
            length: item.maxLength
          });
          itemRule.push({ validator: validator, trigger: ["blur", "change"] });
        }

        if (item.validator) {
          let validatorList =
            typeof item.validator === "string"
              ? [item.validator]
              : item.validator;
          validatorList.forEach(validatorCode => {
            let validator = this.$validator.formRule(validatorCode);
            itemRule.push({
              validator: validator,
              trigger: ["blur", "change"]
            });
          });
        }

        if (itemRule.length) {
          let field = item.fieldList ? item.fieldList[0] : item.field;
          formRules[field] = itemRule;
        }
      });
      this.formRules = formRules;
    },
    // 对表单样式进行默认赋值等初始化的操作
    setFormStyleDefault: function() {
      let {
        itemSpan,
        itemGutter,
        labelWidth,
        prependSpan,
        appendSpan,
        btnWrapSpan,
        btnWrapAlign,
        btnWrapMarginTop
      } = this.formStyle;
      itemSpan = this.isSet(itemSpan) ? parseInt(itemSpan) : 8;
      itemGutter = this.isSet(itemGutter) ? parseInt(itemGutter) : 40;
      labelWidth = this.isSet(labelWidth)
        ? parseInt(labelWidth) + "px"
        : "auto";

      prependSpan = this.isSet(prependSpan) ? parseInt(prependSpan) : 24;
      appendSpan = this.isSet(appendSpan) ? parseInt(appendSpan) : 24;
      btnWrapSpan = this.isSet(btnWrapSpan) ? parseInt(btnWrapSpan) : 24;
      btnWrapAlign = btnWrapAlign || "right";
      btnWrapMarginTop = btnWrapMarginTop || "12px";

      this.style = {
        itemSpan,
        itemGutter,
        labelWidth,
        prependSpan,
        appendSpan,
        btnWrapSpan,
        btnWrapAlign,
        btnWrapMarginTop
      };
    },
    // 通过field获取item对象
    getItem: function(field) {
      return (
        this.formItems.find(v => {
          if (this.isArray(v.fieldList)) {
            return v.fieldList[0] === field;
          } else {
            return v.field === field;
          }
        }) || false
      );
    },
    // 获取item的样式
    getItemStyle: function(item, conf) {
      let style = {};
      if (item.type === "INPUT" && item.fieldList) {
        let inputAlign = conf.inputAlign;
        let leftInputWidth = this.isSet(item.leftInputWidth)
          ? parseInt(item.leftInputWidth)
          : 49;
        leftInputWidth = Math.max(18, leftInputWidth);
        leftInputWidth = Math.min(80, leftInputWidth);
        if (inputAlign === "left") {
          style.float = "left";
          style.width = leftInputWidth + "%";
        }
        if (inputAlign === "right") {
          style.float = "right";
          style.width = 98 - leftInputWidth + "%";
        }
      }
      return style;
    },
    // 清空双字段组件的值
    clearItemValue: function(field) {
      let item = this.getItem(field);
      if (
        (item.type === "INPUT" ||
          item.type === "daterang" ||
          item.type === "outbox") &&
        item.fieldList
      ) {
        let [field1, field2] = item.fieldList;
        this.formData[field1] = "";
        this.formData[field2] = "";
      }

      if (
        (item.type === "daterang" || item.type === "outbox") &&
        item.fieldList
      ) {
        this.baseFormData[item.field] = [];
      }
    },
    // 通过field获取数据值
    getItemValue: function(field) {
      return this.formData[field];
    },
    // 动态获取item对象的placeholder
    getItemPlaceholder: function(item, conf) {
      if (this.pageType === "check") {
        return "";
      }
      if (this.isArray(item.placeholder)) {
        let inputAlign = conf.inputAlign;
        if (inputAlign === "left") {
          return item.placeholder[0];
        }
        if (inputAlign === "right") {
          return item.placeholder[1];
        }
      }
      return item.placeholder;
    },
    // 动态获取item对象的options
    getItemOptions: function(item) {
      if (typeof item.options === "function") {
        return item.options({ item }) || [];
      }
      return item.options || [];
    },
    // 获取日期选择器的配置参数
    getItemDateOptions: function(item) {
      const options = {};
      options.disabledDate = time => {
        if (item.minDate) {
          if (this.isDate(item.minDate)) {
            if (time.getTime() < item.minDate.getTime()) {
              return true;
            }
          }
          if (typeof item.minDate === "string") {
            let value = this.getItemValue(item.minDate);
            if (!value) return false;
            if (value.length === 10) value += " 00:00:00";
            let minDate = new Date(value);
            if (time.getTime() < minDate.getTime()) {
              return true;
            }
          }
        }
        if (item.maxDate) {
          if (this.isDate(item.maxDate)) {
            if (time.getTime() > item.maxDate.getTime()) {
              return true;
            }
          }
          if (typeof item.maxDate === "string") {
            let value = this.getItemValue(item.maxDate);
            if (!value) return false;
            if (value.length === 10) value += " 00:00:00";
            let maxDate = new Date(value);
            if (time.getTime() > maxDate.getTime()) {
              return true;
            }
          }
        }
        return false;
      };

      return options;
    },
    // 设置表单字段是否必填
    setItemRequired: function(field, isRequired) {
      let item = this.getItem(field);
      if (item) {
        item.required = isRequired;
      }
      this.setFormRulesData();
      setTimeout(() => {
        this.$refs["form"].clearValidate();
      }, 0);
    },
    // 设置表单字段校验方式
    setItemValidator: function(field, validator) {
      let item = this.getItem(field);
      if (item) {
        item.validator = validator;
      }
      this.setFormRulesData();
      setTimeout(() => {
        this.$refs["form"].clearValidate();
      }, 0);
    },
    // 设置表单字段最大长度
    setItemMaxLength: function(field, length) {
      let item = this.getItem(field);
      if (item) {
        item.maxLength = length;
      }
      this.setFormRulesData();
      setTimeout(() => {
        this.$refs["form"].clearValidate();
      }, 0);
    },
    // 设置表单字段最小长度
    setItemMinLength: function(field, length) {
      let item = this.getItem(field);
      if (item) {
        item.minLength = length;
      }
      this.setFormRulesData();
      setTimeout(() => {
        this.$refs["form"].clearValidate();
      }, 0);
    },
    // 判断字段组件是否显示
    checkItemShow: function(item) {
      if (typeof item.isShow === "function") {
        return item.isShow({ form: this });
      }
      if (typeof item.isShow === "boolean") {
        return item.isShow;
      }
      return true;
    },
    // 判断字段组件是否禁用状态
    checkItemDisabled: function(item, conf) {
      if (this.readOnly) return true;
      if (item.disabled === true) return true;
      if (typeof item.disabled === "function") {
        return item.disabled();
      }
      if (this.isArray(item.disabled)) {
        let inputAlign = conf.inputAlign;
        if (inputAlign === "left") {
          return item.disabled[0];
        }
        if (inputAlign === "right") {
          return item.disabled[1];
        }
      }
      return false;
    },
    // 约束字段数据值
    resetFieldData: function(item) {
      let row = this.formData;
      if (item.isNumber === true) {
        let number =
          parseFloat(row[item.field]) || parseFloat(row[item.field]) === 0
            ? parseFloat(row[item.field])
            : "";
        if (typeof number === "number") {
          if (typeof item.max === "number") {
            number = Math.min(number, item.max);
          }
          if (typeof item.min === "number") {
            number = Math.max(number, item.min);
          }
          if (typeof item.decimal === "number") {
            number = parseFloat(number.toFixed(item.decimal));
          }
        }
        row[item.field] = number;
      }
    },
    // 设置字段组件关联的子组件值清空【递归】
    setChildDictionaryClear: function(item) {
      this.formData[item.childDictionary] = "";
      let childItem = this.getItem(item.childDictionary);
      if (childItem.type === "select" && childItem.childDictionary) {
        this.setChildDictionaryClear(childItem);
      }
    },
    // outbox打开弹框时处理方法
    onOutboxOpen: function(item, data) {
      if (typeof item.onOpen === "function") {
        let value = this.baseFormData[item.field] || this.formData[item.field];
        data.form = this;
        data.item = item;
        data.value = value;
        item.onOpen(data);
      }
    },
    // 当字段数据发生改变时做的处理
    onItemDataChange: function(item, type, selectList) {
      if (item.type === "daterang") {
        let [startField, endField] = item.fieldList;
        if (this.baseFormData[item.field]) {
          let [startDate, endDate] = this.baseFormData[item.field];
          this.formData[startField] = item.autoTime
            ? startDate + " 00:00:00"
            : startDate;
          this.formData[endField] = item.autoTime
            ? endDate + " 23:59:59"
            : endDate;
        } else {
          this.formData[startField] = "";
          this.formData[endField] = "";
        }
      }
      if (item.type === "outbox" && item.fieldList) {
        let [valueField, labelField] = item.fieldList;
        if (this.baseFormData[item.field]) {
          let [value, label] = this.baseFormData[item.field];
          this.formData[valueField] = value;
          this.formData[labelField] = label;
        } else {
          this.formData[valueField] = "";
          this.formData[labelField] = "";
        }
      }
      if (item.type === "SELECT" && item.childDictionary) {
        this.setChildDictionaryClear(item);
      }
      if (type !== "INPUT") {
        this.resetFieldData(item);
      }
      let value = this.baseFormData[item.field] || this.formData[item.field];
      if (typeof item.onChange === "function") {
        item.onChange({ value, item, selectList, form: this });
      }
    },
    // 组件点击事件
    onItemClick: function(item) {
      let value = this.baseFormData[item.field] || this.formData[item.field];
      if (typeof item.onClick === "function") {
        item.onClick({ value, item, form: this });
      }
    },
    // 组件获取焦点事件
    onItemFocus: function(item) {
      let value = this.baseFormData[item.field] || this.formData[item.field];
      if (typeof item.onFocus === "function") {
        item.onFocus({ value, item, form: this });
      }
    },
    // 组件失去焦点事件
    onItemBlur: function(item) {
      let value = this.baseFormData[item.field] || this.formData[item.field];
      if (typeof item.onBlur === "function") {
        item.onBlur({ value, item, form: this });
      }
    },
    resetForm: function() {
      console.log(11111111, this.formData);
      this.$refs["form"].resetFields();
      this.setFormData();
      console.log(222, this.formData);
      for (let field in this.formResetData) {
        this.formData[field] = this.formResetData[field];
      }
      for (let field in this.baseFormResetData) {
        this.baseFormData[field] = JSON.parse(this.baseFormResetData[field]);
      }
    }
  },
  created() {
    this.setFormItemsData();
    this.setFormData();
    this.setFormResetData();
    this.setFormRulesData();
    this.setFormStyleDefault();
  },
  mounted() {
    this.$on("resetForm", this.resetForm);
  }
};
</script>
<style lang="scss" scoped>
.default-search-form {
  background-color: white;
  padding-right: 10px;
}
.el-form /deep/ {
  width: 100%;
  overflow-x: hidden;
  padding-top: 10px;
  .el-button {
    margin-bottom: 8px;
  }
}
.el-select {
  width: 100%;
  max-width: 300px;
  width: 232px;
}
.el-input {
  max-width: 300px;
  width: 232px;
}
.el-date-editor {
  width: 100%;
  max-width: 300px;
  width: 232px;
}
</style>
